package neurons;

import java.util.HashSet;
import java.util.Set;

public class Neuron implements NeuronInterface {

	private FunctionInterface function;

	private Set<ConnectionInterface> incomingConnexions;
	private Set<ConnectionInterface> outgoingConnexions;
	private Set<SignalInterface> signals;

	public Neuron(FunctionInterface function) {
		this.function = function;
		incomingConnexions = new HashSet<ConnectionInterface>();
		outgoingConnexions = new HashSet<ConnectionInterface>();
		signals = new HashSet<SignalInterface>();
	}

	@Override
	public void sendConnectionTo(NeuronInterface targetNeuron) {
		Double rd = Math.random();
		ConnectionInterface newConnection = new Connection(this, targetNeuron,
				rd);
		targetNeuron.acceptConnection(newConnection);
		outgoingConnexions.add(newConnection);
	}

	@Override
	public void propagate(SignalInterface signal) {
		signals.add(signal);

		if (signals.size() == incomingConnexions.size()) {
			SignalInterface weightedSignal = aggregateSignals();
			SignalInterface transformedSignal = function
					.transform(weightedSignal);
			transmit(transformedSignal);
		}
	}

	private SignalInterface aggregateSignals() {
		Double data = new Double(0);
		for (SignalInterface signal : signals) {
			data = signal.getData() * signal.getData();

		}
		return new Signal(data);
	}

	private void transmit(SignalInterface signal) {
		for (ConnectionInterface connection : outgoingConnexions) {
			connection.transmit(signal);
		}
	}

	@Override
	public void acceptConnection(ConnectionInterface newConnection) {
		incomingConnexions.add(newConnection);
	}

	@Override
	public void adaptCoeff(ResultInterface result) {
		switch (result.getResultStatus()) {
		case INCORRECT:

			function.adaptCoeff(result.getDelta());
			break;
		case CORRECT:
			break;
		default:
			break;
		}
	}
}
